'use client';

import React from 'react';
import { AlertTriangle, RefreshCw } from 'lucide-react';

import { Button } from './button';

interface ErrorBoundaryProps {
  children: React.ReactNode;
  fallback?: React.ComponentType<ErrorFallbackProps>;
}

interface ErrorFallbackProps {
  error: Error;
  resetError: () => void;
}

interface ErrorBoundaryState {
  hasError: boolean;
  error: Error | null;
}

export class ErrorBoundary extends React.Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  constructor(props: ErrorBoundaryProps) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static override getDerivedStateFromError(error: Error): ErrorBoundaryState {
    return { hasError: true, error };
  }

  override componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('Error caught by boundary:', error, errorInfo);
  }

  resetError = () => {
    this.setState({ hasError: false, error: null });
  };

  render() {
    if (this.state.hasError) {
      const FallbackComponent = this.props.fallback || DefaultErrorFallback;
      return (
        <FallbackComponent
          error={this.state.error!}
          resetError={this.resetError}
        />
      );
    }

    return this.props.children;
  }
}

function DefaultErrorFallback({ error, resetError }: ErrorFallbackProps) {
  return (
    <div className="border-destructive/20 bg-destructive/5 flex min-h-[400px] flex-col items-center justify-center space-y-4 rounded-lg border p-8 text-center">
      <div className="bg-destructive/10 rounded-full p-3">
        <AlertTriangle className="text-destructive h-6 w-6" />
      </div>

      <div className="space-y-2">
        <h2 className="text-destructive text-lg font-semibold">
          Something went wrong
        </h2>
        <p className="text-muted-foreground max-w-md text-sm">
          {error.message || 'An unexpected error occurred. Please try again.'}
        </p>
      </div>

      <Button onClick={resetError} variant="outline" size="sm">
        <RefreshCw className="mr-2 h-4 w-4" />
        Try again
      </Button>

      {process.env.NODE_ENV === 'development' && (
        <details className="mt-4 max-w-lg">
          <summary className="text-muted-foreground cursor-pointer text-xs">
            Error details
          </summary>
          <pre className="bg-muted mt-2 whitespace-pre-wrap rounded p-2 text-left text-xs">
            {error.stack}
          </pre>
        </details>
      )}
    </div>
  );
}

// 高阶组件包装器
export function withErrorBoundary<P extends object>(
  Component: React.ComponentType<P>,
  fallback?: React.ComponentType<ErrorFallbackProps>
) {
  const WrappedComponent = (props: P) => (
    <ErrorBoundary fallback={fallback}>
      <Component {...props} />
    </ErrorBoundary>
  );

  WrappedComponent.displayName = `withErrorBoundary(${
    Component.displayName || Component.name || 'Component'
  })`;

  return WrappedComponent;
}
